// array.hxx


#ifndef _BLOGS_ARRAY
#define _BLOGS_ARRAY


#include <cstdio>

#include <initializer_list>
#include <memory>


namespace blogs
{


using std::default_delete;
using std::initializer_list;
using std::shared_ptr;


template <class _T>
class Array
{

  private:

    int
    __size__;


    shared_ptr<_T>
    __buffer__;


  public:

    Array(int size = 0)
        : __size__(size), __buffer__(nullptr)
    {
        //std::printf("\n%p Array::Array(int) called.\n", this);
        if (__size__ < 0)
            throw;
        __buffer__ = shared_ptr<_T>(new _T[__size__] {},
                                    default_delete<_T[]>());
    }


    Array(initializer_list<_T> init)
        : __size__(init.size()), __buffer__(nullptr)
    {
        //std::printf("\n%p Array::Array(initializer_list<_T>) called.\n", this);
        __buffer__ = shared_ptr<_T>(new _T[__size__] {},
                                    default_delete<_T[]>());
        int i = 0;
        for (_T x : init)
            __buffer__.get()[i++] = x;
    }


    Array(Array const& other)
        : __size__(other.__size__), __buffer__(other.__buffer__)
    {
        //std::printf("\n%p Array::Array(Array const&) called.\n", this);
    }


    Array(Array && other)
        : __size__(other.__size__), __buffer__(other.__buffer__)
    {
        //std::printf("\n%p Array::Array(Array &&) called.\n", this);
        other.__size__ = 0;
        other.__buffer__ = nullptr;
    }


    ~Array()
    {
        //std::printf("\n%p Array::~Array() called.\n", this);
    }


    Array &
    operator=(Array const& other)
    {
        //std::printf("\n%p Array::operator=(Array const&) called.\n", this);
        if (this == &other)
            return *this;
        __size__ = other.__size__;
        __buffer__ = other.__buffer__;
        return *this;
    }


    Array &
    operator=(Array && other)
    {
        //std::printf("\n%p Array::operator=(Array &&) called.\n", this);
        if (this == &other)
            return *this;
        __size__ = other.__size__;
        __buffer__ = other.__buffer__;
        other.__size__ = 0;
        other.__buffer__ = nullptr;
        return *this;
    }


    int
    size() const
    {
        return __size__;
    }


    _T const&
    operator[](int idx) const
    {
        return __buffer__.get()[idx];
    }


    _T &
    operator[](int idx)
    {
        return const_cast<_T &>(static_cast<Array const&>(*this)[idx]);
    }


    _T const*
    begin() const
    {
        return __buffer__.get();
    }


    _T *
    begin()
    {
        return const_cast<_T *>(static_cast<Array const&>(*this).begin());
    }


    _T const*
    end() const
    {
        return __buffer__.get() + __size__;
    }


    _T *
    end()
    {
        return const_cast<_T *>(static_cast<Array const&>(*this).end());
    }

};


} // end of namespace blogs


#endif

